package com.rhb.ca.web.util;

import org.xml.sax.InputSource;
import org.w3c.dom.Element;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.w3c.dom.Node;

import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.SAXException;


// jaxp 1.0.1 imports
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;

import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;


public class SignOnDAO {

    // xml tag constants
    public static final String SIGNON_PAGE = "signon-page";
    public static final String SIGNOUT_PAGE = "signout-page";
    public static final String SIGNON_SUCCESS_PAGE = "signon-success-page";
    public static final String SIGNON_ERROR_PAGE = "signon-error-page";
    public static final String FORBIDDEN_PAGE = "forbidden-page";
    
    public static final String SECURITY_CONSTRAINT = "security-constraint";
    public static final String WEB_RESOURCE_NAME = "web-resource-name";
    public static final String WEB_RESOURCE_COLLECTION = "web-resource-collection";
    public static final String URL_PATTERN = "url-pattern";
    public static final String AUTH_CONSTRAINT = "auth-constraint";
    public static final String ROLE_NAME = "role-name";

    private String signOnPage = null;
    private String signOutPage = null;
    private String signOnSuccessPage = null;
    private String signOnErrorPage = null;
    private String forbiddenPage = null;
    
    private HashMap protectedResources = null;
	
	private String signOnConfigFile = null;
	
    public SignOnDAO(URL configURL) {
    	signOnConfigFile = configURL.toString();
    	
        Element root = loadDocument(configURL);
        protectedResources = getProtectedResources(root);
    }

    public String getSignOnPage() {
        return signOnPage;
    }
    
    public String getSignOutPage() {
        return signOutPage;
    }
    
    
    public String getSignOnSuccessPage() {
        return signOnSuccessPage;
    }


    public String getSignOnErrorPage() {
        return signOnErrorPage;
    }
    
    public String getForbiddenPage() {
        return forbiddenPage;
    }
    
    public HashMap getProtectedResources() {
        return protectedResources;
    }

    private  Element loadDocument(URL url) {
        Document doc = null;
        try {
            InputSource xmlInp = new InputSource(url.openStream());

            DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder parser = docBuilderFactory.newDocumentBuilder();
            doc = parser.parse(xmlInp);
            Element root = doc.getDocumentElement();
            root.normalize();
            return root;
        } catch (SAXParseException err) {
            System.err.println ("SignOnDAO ** Parsing error" + ", line " +
                        err.getLineNumber () + ", uri " + err.getSystemId ());
            System.err.println("SignOnDAO error: " + err.getMessage ());
        } catch (SAXException e) {
            System.err.println("SignOnDAO error: " + e);
        } catch (java.net.MalformedURLException mfx) {
            System.err.println("SignOnDAO error: " + mfx);
        } catch (java.io.IOException e) {
            System.err.println("SignOnDAO error: " + e);
        } catch (Exception pce) {
            System.err.println("SignOnDAO error: " + pce);
        }
        return null;
    }

    private HashMap getProtectedResources(Element root) {
        HashMap resources = new HashMap();
        
        // get the signon page and signon error page
        signOnPage = getTagValue(root, SIGNON_PAGE).trim();
        signOutPage = getTagValue(root, SIGNOUT_PAGE).trim();
        signOnSuccessPage = getTagValue(root, SIGNON_SUCCESS_PAGE).trim();
        signOnErrorPage = getTagValue(root, SIGNON_ERROR_PAGE).trim();
        forbiddenPage = getTagValue(root, FORBIDDEN_PAGE).trim();

        // get protected info//
        NodeList outterList = root.getElementsByTagName(SECURITY_CONSTRAINT);
        
        for (int outterLoop = 0; outterLoop < outterList.getLength(); outterLoop++) {
            Element element = (Element)outterList.item(outterLoop);
            
            // get web-resource-name
			String resourceName = getSubTagValue(element, WEB_RESOURCE_NAME);
			
            // get roles
            ArrayList roles = new ArrayList();
            NodeList roleList = element.getElementsByTagName(AUTH_CONSTRAINT);
            for (int roleLoop = 0; roleLoop < roleList.getLength(); roleLoop++) {
                Node  roleNode = roleList.item(roleLoop);
                ArrayList roleNames = getSubTagValues(roleNode, ROLE_NAME);
                if ((roleNames != null)){
                	roles.addAll(roleNames);
                }
            }

			// get resources' url-patterns
            ArrayList urlPatterns = new ArrayList();
            NodeList urlPatternList = element.getElementsByTagName(WEB_RESOURCE_COLLECTION);
            for (int urlPatternLoop = 0; urlPatternLoop < urlPatternList.getLength(); urlPatternLoop++) {
                        Node  urlPatternNode = urlPatternList.item(urlPatternLoop);
                        ArrayList ts = getSubTagValues(urlPatternNode, URL_PATTERN);
                        //System.out.println("url-pattern = " + urlPattern);
                        if ((ts != null)){
                        	urlPatterns.addAll(ts);
                        }
            }
			
			ProtectedResource resource = new ProtectedResource(resourceName, urlPatterns, roles);
            
            //System.out.println(resource);
                    
            if (!resources.containsKey(resourceName)) {
                 resources.put(resourceName, resource);
            } else {
                System.err.println("*** Non Fatal errror: web-resource-name '" + resourceName +
                               "' defined more than once in " + signOnConfigFile);
            }
                                
        }
        return resources;
    }
    
    

    private String getSubTagValue(Node node, String subTagName) {
        String returnString = "";
        if (node != null) {
            NodeList  children = node.getChildNodes();
            for (int innerLoop =0; innerLoop < children.getLength(); innerLoop++) {
                Node  child = children.item(innerLoop);
                if ((child != null) && (child.getNodeName() != null) && child.getNodeName().equals(subTagName) ) {
                    Node grandChild = child.getFirstChild();
                    if (grandChild.getNodeValue() != null) return grandChild.getNodeValue();
                }
            } // end inner loop
        }
        return returnString;
    }


    private ArrayList getSubTagValues(Node node, String subTagName) {
    	
    	//System.out.println("node.getNodeName()="+node.getNodeName());
    	
        ArrayList returnA = new ArrayList();
        if (node != null) {
            NodeList  children = node.getChildNodes();
            for (int innerLoop =0; innerLoop < children.getLength(); innerLoop++) {
                Node  child = children.item(innerLoop);
                if ((child != null) && (child.getNodeName() != null) && child.getNodeName().equals(subTagName) ) {
                    Node grandChild = child.getFirstChild();
                    if (grandChild.getNodeValue() != null){
		                //System.out.println("roleName = " + grandChild.getNodeValue());
                    	returnA.add(grandChild.getNodeValue());
                    }
                }
            }
        }
        return returnA;
    }


    private String getTagValue(Element root, String tagName) {
        String returnString = "";
        NodeList list = root.getElementsByTagName(tagName);
        for (int loop = 0; loop < list.getLength(); loop++) {
            Node node = list.item(loop);
            if (node != null) {
                Node child = node.getFirstChild();
                if ((child != null) && child.getNodeValue() != null) return child.getNodeValue();
            }
        }
        return returnString;
    }
}


